package com.gexiaobao.pigeon.ui.fragment.mine.pigeon.activity

import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.text.TextUtils
import android.view.Window
import android.view.WindowManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import cn.qqtheme.framework.picker.OptionPicker
import cn.qqtheme.framework.widget.WheelView
import com.alibaba.sdk.android.oss.ClientConfiguration
import com.alibaba.sdk.android.oss.OSSClient
import com.alibaba.sdk.android.oss.common.auth.OSSStsTokenCredentialProvider
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.gexiaobao.pigeon.R
import com.gexiaobao.pigeon.app.base.BaseActivity
import com.gexiaobao.pigeon.app.eventViewModel
import com.gexiaobao.pigeon.app.ext.Constant
import com.gexiaobao.pigeon.app.ext.showMessage
import com.gexiaobao.pigeon.app.model.bean.AddVisitVideoResponse
import com.gexiaobao.pigeon.app.model.bean.InfoByRingSnResponse
import com.gexiaobao.pigeon.app.model.bean.ScanVisitDataResponse
import com.gexiaobao.pigeon.app.model.param.EditVisitVideoParam
import com.gexiaobao.pigeon.app.rxui.tablayout.listener.GlideEngine
import com.gexiaobao.pigeon.app.util.FileUtil
import com.gexiaobao.pigeon.app.util.MultipartUploader
import com.gexiaobao.pigeon.app.util.PictureUtil
import com.gexiaobao.pigeon.app.util.RxToast
import com.gexiaobao.pigeon.app.util.StatusBarUtil
import com.gexiaobao.pigeon.app.util.WebSocketUtils
import com.gexiaobao.pigeon.databinding.ActivityUploadVideoPigeonBinding
import com.gexiaobao.pigeon.permissions.PermissionInterceptor
import com.gexiaobao.pigeon.ui.activity.VideoCaptureActivity
import com.gexiaobao.pigeon.ui.dialog.RxDialogProgressBar
import com.gexiaobao.pigeon.viewmodel.ShedPigeonViewModel
import com.google.gson.Gson
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.kongzue.dialogx.dialogs.PopNotification
import com.kongzue.dialogx.util.TextInfo
import com.loan.golden.cash.money.videocompress.VideoCompressUtils
import com.loan.golden.cash.money.videocompress.VideoMetadata
import com.loan.golden.cash.money.videocompress.VideoUtils
import com.luck.picture.lib.basic.PictureSelector
import com.luck.picture.lib.config.PictureConfig
import com.luck.picture.lib.config.SelectMimeType
import com.luck.picture.lib.config.SelectModeConfig
import com.luck.picture.lib.config.SelectorConfig
import com.luck.picture.lib.config.SelectorProviders
import com.luck.picture.lib.engine.VideoPlayerEngine
import com.luck.picture.lib.entity.LocalMedia
import com.luck.picture.lib.interfaces.OnResultCallbackListener
import com.luck.picture.lib.service.ForegroundService
import com.luck.picture.lib.thread.PictureThreadUtils
import com.luck.picture.lib.utils.MediaStoreUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import me.hgj.jetpackmvvm.base.appContext
import me.hgj.jetpackmvvm.ext.util.setOnclickNoRepeat
import me.hgj.jetpackmvvm.util.LogUtils
import me.hgj.jetpackmvvm.util.startActivity
import me.hgj.jetpackmvvm.util.startActivityForResult
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import org.json.JSONObject
import java.io.File


/**
 * @Author      : hxw
 * @Date        : 2024/6/11 17:28
 * @Describe    : 上传探视视频
 */
open class ActivityUploadPigeonVideo : BaseActivity<ShedPigeonViewModel, ActivityUploadVideoPigeonBinding>() {

    private var mOrgId = ""
    private var mAccessKeyId = ""
    private var mAccessKeySecret = ""
    private var mSecurityToken = ""
    private val bucketName = "pigeon-ms"
    private var objectKey = "base_api/visit_video/"
    private var ringId: String = ""
    private var videoUrl: String = ""
    private val deviceList: ArrayList<String> = arrayListOf()
    private var mPosition = 0//记录选中位置
    private var pigeonVideoFile: File? = null
    private var mPigeonId = 0
    private var mRaceId = 0
    private var editId = 0
    private var type = 0////1-修改 2-新增
    private var selectVideo: Uri? = null
    private var isEditor = false

    private val videoPlayerEngine: VideoPlayerEngine<*>? = null
    private var selectorConfig: SelectorConfig? = null
    private lateinit var dialogPro: RxDialogProgressBar
    private lateinit var webSocketUtils: WebSocketUtils

    private fun refreshUiData(it: InfoByRingSnResponse) {
        if (it.err.isNotEmpty()) {
            showMessage(it.err)
            return
        }
        editId = it.id
        mPigeonId = it.pigeonId
        mDatabind.data = it
        type = if (it.path.isEmpty()) {
            2
        } else {
            1
        }
        mDatabind.llDialogPigeonInfo.isVisible = true
        mDatabind.tvVisitType.text = when (it.visitType) {
            1 -> "现场探视"
            2 -> "视频探视"
            else -> "不探视"
        }
        ringId = it.ringId
        videoUrl = it.path
        showVideoImage(videoUrl)
    }

    override fun initView(savedInstanceState: Bundle?) {
        StatusBarUtil.setTranslucentForImageView(this, 0, null)
        selectorConfig = SelectorProviders.getInstance().selectorConfig
        mDatabind.includeBar.tvTitle.text = "上传探视视频"
        mViewModel.getOssSts()
        mOrgId = intent.getStringExtra("orgId").toString()
        type = intent.getIntExtra("type", 0)
        mRaceId = intent.getIntExtra("raceId", 0)
        editId = intent.getIntExtra("id", 0)
        videoUrl = intent.getStringExtra("path").toString()
        val ringSn = intent.getStringExtra("ringSn").toString()
        showVideoImage(videoUrl)
        mViewModel.getGatherDeviceList()
        if (ringSn.isNotEmpty()) {
            isEditor = true
            mDatabind.llScanDevice.isGone = true
            mViewModel.getInfoByRingSn(ringSn, mRaceId)
        }

        mDatabind.llDialogPigeonInfo.isVisible = true//type == 1
    }

    override fun onBindViewClick() {
        super.onBindViewClick()
        setOnclickNoRepeat(
            mDatabind.tvScanPigeonClock,
            mDatabind.ivScanPigeonClock,
            mDatabind.includeBar.ivBack,
            mDatabind.rlVisitVideo,
            mDatabind.tvRecordVideo,
            mDatabind.tvPhotoAlbumVideo
        ) { it ->
            when (it) {
                mDatabind.tvPhotoAlbumVideo -> albumVideo()
                mDatabind.tvRecordVideo -> {
                    val deviceCode = mDatabind.tvScanPigeonClock.text.toString().trim()
                    if (deviceCode.isEmpty() && !isEditor) {
                        RxToast.showToast("请先连接设备并扫描赛鸽")
                        return@setOnclickNoRepeat
                    }
                    XXPermissions.with(this)
                        .permission(Permission.CAMERA)
                        .interceptor(PermissionInterceptor())
                        .request { _, allGranted ->
                            if (allGranted) {
                                startActivityForResult<VideoCaptureActivity> {
                                    if (it != null) {
                                        val videoFile = it.getStringExtra("videoFile").toString()
                                        analyticalSelectResults(videoFile)
                                    }
                                }
//                                takeCameraVideo()
                            }
                        }
                }

                mDatabind.rlVisitVideo -> {
                    if (videoUrl.isEmpty()) {
                        RxToast.showToast("暂无视频")
                        return@setOnclickNoRepeat
                    }
                    startActivity<ActivityVideoPlayer>("videoUrl" to videoUrl, "title" to ringId, "type" to "upload")
                }

                mDatabind.includeBar.ivBack -> finish()
                mDatabind.tvScanPigeonClock, mDatabind.ivScanPigeonClock -> showPicker()
            }
        }
    }

    private fun takeCameraVideo() {
        val cameraIntent = Intent(MediaStore.ACTION_VIDEO_CAPTURE)
        if (cameraIntent.resolveActivity(this.packageManager) != null) {
            selectorConfig?.let { ForegroundService.startForegroundService(appContext, it.isCameraForegroundService) }
            val videoUri = MediaStoreUtils.createCameraOutVideoUri(appContext, selectorConfig)
            if (videoUri != null) {
                cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri)
                if (selectorConfig?.isCameraAroundState == true) {
                    cameraIntent.putExtra(PictureConfig.CAMERA_FACING, PictureConfig.CAMERA_BEFORE)
                }
                selectorConfig?.let { cameraIntent.putExtra(PictureConfig.EXTRA_QUICK_CAPTURE, it.isQuickCapture) }
                selectorConfig?.let { cameraIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, it.recordVideoMaxSecond) }
                selectorConfig?.let { cameraIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, it.videoQuality) }
                videoCaptureLauncher.launch(cameraIntent)
            }
        }
    }

//    private fun startCamera() {
//        cameraProviderFuture = ProcessCameraProvider.getInstance(this)
//        cameraProviderFuture.addListener({
//            val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
//            // Setup Preview and VideoCapture
//            val preview = Preview.Builder().build().also {
//                it.setSurfaceProvider(findViewById<VideoView>(R.id.viewFinder).surfaceProvider)
//            }
//            videoCapture = withOutput(FileOutputOptions.Builder(createVideoFile()).build())
//            val cameraSelector = if (isFrontFacing) CameraSelector.DEFAULT_FRONT_CAMERA else CameraSelector.DEFAULT_BACK_CAMERA
//            try {
//                cameraProvider.unbindAll()
//                cameraProvider.bindToLifecycle(this, cameraSelector, preview, videoCapture)
//            } catch (exc: Exception) {
//                Log.e("TAG", "Use case binding failed", exc)
//            }
//
//        }, ContextCompat.getMainExecutor(this))
//    }

    private fun createVideoFile(): File {
        val videoFolder = getExternalFilesDir(null)
        return File.createTempFile("VID_${System.currentTimeMillis()}", ".mp4", videoFolder)
    }

    private val videoCaptureLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        when (result.resultCode) {
            RESULT_OK -> dispatchHandleCamera(result.data)
            RESULT_CANCELED -> {}
            else -> println("未知操作或录像失败")
        }
    }

    private fun dispatchHandleCamera(intent: Intent?) {
        PictureThreadUtils.executeByIo<LocalMedia>(object : PictureThreadUtils.SimpleTask<LocalMedia?>() {
            override fun doInBackground(): LocalMedia? {
                val outputPath: String = PictureUtil.getOutputPath(intent, selectorConfig)
                if (!TextUtils.isEmpty(outputPath)) {
                    selectorConfig!!.cameraPath = outputPath
                }
                if (TextUtils.isEmpty(selectorConfig!!.cameraPath)) {
                    return null
                }
                if (selectorConfig!!.chooseMode == SelectMimeType.ofAudio()) {
                    PictureUtil.copyOutputAudioToDir(selectorConfig!!)
                }
                val media: LocalMedia = PictureUtil.buildLocalMedia(selectorConfig!!.cameraPath, selectorConfig!!)
                media.isCameraSource = true
                return media
            }

            override fun onSuccess(result: LocalMedia?) {
                PictureThreadUtils.cancel(this)
                if (result != null) {
                    PictureUtil.onScannerScanFile(result, this@ActivityUploadPigeonVideo)
                    if (result.realPath.isNotEmpty()) {
                        analyticalSelectResults(result.realPath)//, result.width, result.height
                    }
                }
                selectorConfig!!.cameraPath = ""
            }
        })
    }

    private fun albumVideo() {
        val deviceCode = mDatabind.tvScanPigeonClock.text.toString().trim()
        if (deviceCode.isEmpty() && !isEditor) {
            RxToast.showToast("请先连接设备并扫描赛鸽")
            return
        }
        PictureSelector.create(this)
            .openGallery(SelectMimeType.ofVideo())
            .setMaxSelectNum(1)
            .setMinSelectNum(1)
            .setVideoPlayerEngine(videoPlayerEngine)
            .isDisplayCamera(true)//是否打开摄像按钮
            .isMaxSelectEnabledMask(true)//是否显示蒙层（达到最大可选数量）
            .setImageEngine(GlideEngine.createGlideEngine())
            .setCompressEngine(PictureUtil.getCompressFileEngine())
            .setPermissionDescriptionListener(PictureUtil.getPermissionDescriptionListener())
            .setPermissionDeniedListener(PictureUtil.getPermissionDeniedListener())
            .setImageSpanCount(3)
            .setVideoThumbnailListener(PictureUtil.getVideoThumbnailEventListener())
            .isAutoVideoPlay(true)
            .isLoopAutoVideoPlay(false)
            .isUseSystemVideoPlayer(true)
            .isDirectReturnSingle(true)
            .setSelectionMode(SelectModeConfig.SINGLE)//单选or多选
            .isVideoPauseResumePlay(true)
            .isPreviewVideo(true)
            .setMaxVideoSelectNum(1)
            .forResult(object : OnResultCallbackListener<LocalMedia> {
                override fun onResult(result: ArrayList<LocalMedia>?) {
                    if (!result.isNullOrEmpty())
                        analyticalSelectResults(result[0].realPath)//result[0].width, result[0].height
                }

                override fun onCancel() {}
            })
    }

    override fun createObserver() {
        super.createObserver()
        mViewModel.getCleanResult.observe(this) {
            dismissLoading()
            openWebSocket(it.cleanId)
        }
        /** 获取sts */
        mViewModel.ossStsResult.observe(this) {
            mAccessKeyId = it.accessKeyId
            mAccessKeySecret = it.accessKeySecret
            mSecurityToken = it.securityToken
        }
        /** 修改探视视频 */
        mViewModel.editVisitVideoResult.observe(this) {
            finishToRefreshData()
        }
        /** 上传探视视频 */
        mViewModel.addVisitVideoResult.observe(this) {
            finishToRefreshData()
        }
        /** 获取足环信息 */
        mViewModel.infoByRingSnResult.observe(this) {
            mDatabind.data = it
            refreshUiData(it)
            if (it != null) {
                editId = it.id
                mPigeonId = it.pigeonId
                type = if (it.path.isEmpty()) {
                    2
                } else {
                    1
                }
                mDatabind.llDialogPigeonInfo.isVisible = true
                mDatabind.tvVisitType.text = when (it.visitType) {
                    1 -> "现场探视"
                    2 -> "视频探视"
                    else -> "不探视"
                }
                ringId = it.ringId
                videoUrl = it.path
                showVideoImage(videoUrl)
            }
        }
        /** 获取组织方所有设备 */
        mViewModel.deviceResult.observe(this) {
            deviceList.clear()
            if (!it.isEmpty()) {
                it.info.forEachIndexed { _, list ->
                    deviceList.add(list.imsi)
                }
            }
        }
    }


    private fun showDialog() {
        PopNotification.build()
            .setMessage("已开启，请开始扫描您的爱鸽")
            .setBackgroundColor(ContextCompat.getColor(this, R.color.white))
            .setMessageTextInfo(TextInfo().setBold(true).setFontColor(ContextCompat.getColor(this, R.color.black)).setFontSize(20))
            .setOnPopNotificationClickListener { _, _ ->
//                PopTip.tip("点击了通知" + dialog.dialogKey())
                true
            }
            .show()
    }

    /**
     * ws://10.10.15.243:10082/r/v1/clean/cleanWs?&cleanId=3&imsi=460087438705643
     * Constant.SOCKET_URL_BASE + "/u/v1/visit/createVideoSocket?imsi=$deviceCode&raceId=$mRaceId&connType=5&platform=android"
     * */
    private fun openWebSocket(mCleanId: Int) {
        val deviceCode = mDatabind.tvScanPigeonClock.text.toString().trim()
        val url = Constant.SOCKET_URL_RACE + "/r/v1/clean/cleanWs?cleanId=$mCleanId&imsi=$deviceCode"
        webSocketUtils = WebSocketUtils(url,
            object : WebSocketListener() {
                override fun onOpen(webSocket: WebSocket, response: Response) {
                    super.onOpen(webSocket, response)
                    LogUtils.debugInfo("ActivityUploadPigeonVideo=====onOpen" + response.message)
                }

                override fun onMessage(webSocket: WebSocket, text: String) {
                    super.onMessage(webSocket, text)
                    if (text.isNotEmpty()) {
                        val jsonData = JSONObject(text).toString()
                        val result = Gson().fromJson(jsonData, ScanVisitDataResponse::class.java)
                        mViewModel.getInfoByRingSn(result.ringSn, mRaceId)
                    }
                }

                override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                    super.onClosed(webSocket, code, reason)
                    webSocketUtils.endHeart()
                }

                override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                    super.onClosing(webSocket, code, reason)
                    webSocketUtils.endHeart()
                }

                override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                    super.onFailure(webSocket, t, response)
                    webSocketUtils.endHeart()
                    webSocketUtils.reConnect()
                }
            })
        webSocketUtils.startHeart("", 10000)

    }

    private fun finishToRefreshData() {
        showVideoImage(videoUrl)
        eventViewModel.toRefreshData.value = true
        RxToast.success("上传成功")
    }

    private fun showVideoImage(videoPath: String) {
        Glide.with(this)
            .setDefaultRequestOptions(
                RequestOptions()
                    .frame(0)
                    .centerCrop()
            )
            .load(videoPath)
            .apply(RequestOptions.bitmapTransform(RoundedCorners(20)))
            .into(mDatabind.ivVideoPic)
    }

    private fun showPicker() {
        if (deviceList.isEmpty()) {
            showMessage("设备获取失败，请重试")
            return
        }
        val picker = OptionPicker(this@ActivityUploadPigeonVideo, deviceList)
        picker.setCanceledOnTouchOutside(false)
        picker.setDividerRatio(WheelView.DividerConfig.FILL)
        picker.setShadowColor(ContextCompat.getColor(this, R.color.bg_light_bllue), 40)
        picker.selectedIndex = mPosition
        picker.setCycleDisable(true)
        picker.setTitleText("请选择羽色")
        picker.setTitleTextColor(Color.BLACK)
        picker.setTitleTextSize(18)
        picker.setSubmitText("确认")
        picker.setSubmitTextSize(17)
        picker.setSubmitTextColor(ContextCompat.getColor(this, R.color.bg_light_bllue))//确定按钮文字颜色
        picker.setCancelText("取消")
        picker.setCancelTextSize(17)
        picker.setCancelTextColor(ContextCompat.getColor(this, R.color.bg_light_bllue))//取消按钮文字颜色
        picker.setTextSize(18)
        picker.setLineSpaceMultiplier(3.0F)
        picker.setOnOptionPickListener(object : OptionPicker.OnOptionPickListener() {
            override fun onOptionPicked(index: Int, item: String) {
                mDatabind.tvScanPigeonClock.text = item
                mPosition = index
                if (isInteger(mOrgId)) {
                    showLoading(getString(R.string.loading))
                    mViewModel.getCleaning(mOrgId.toInt())
                }
            }
        })
        val window: Window = picker.window
        val lp: WindowManager.LayoutParams = window.attributes
        lp.width = WindowManager.LayoutParams.MATCH_PARENT
        picker.setWidth(WindowManager.LayoutParams.MATCH_PARENT)
        picker.show()
    }

    private fun analyticalSelectResults(path: String) {//outWidth: Int, outHeight: Int
        pigeonVideoFile = File(path)
        LogUtils.warnInfo("压缩前：" + FileUtil.formatFileSize(FileUtil.getFileSize(pigeonVideoFile)))
        selectVideo = FileProvider.getUriForFile(this, this.packageName + ".provider", pigeonVideoFile!!)
        if (selectVideo == null || path.isEmpty()) {
            RxToast.showToast("请选择视频文件")
            return
        }
        showProgressBarDialog()
        val cache = if (externalCacheDir != null) externalCacheDir else cacheDir
        val dir = File(cache, "video")
        val fileName = "${System.currentTimeMillis()}.mp4"

        VideoCompressUtils.compress(this, selectVideo, dir, fileName, object : com.loan.golden.cash.money.videocompress.VideoCompressCallback {
            override fun onComplete(output: File) {
                LogUtils.warnInfo("压缩后：" + FileUtil.formatFileSize(FileUtil.getFileSize(output)))
                parseCompressInfo(output)
                videoUrl = output.path
                if (::dialogPro.isInitialized) {
                    dialogPro.dismiss()
                    dialogPro.dismiss()
                }
                objectKey = objectKey + mRaceId + "/" + mRaceId + "+" + System.currentTimeMillis() + output.name
                showLoading("上传中...")
                val credentialProvider = OSSStsTokenCredentialProvider(mAccessKeyId, mAccessKeySecret, mSecurityToken)
                val conf = ClientConfiguration().apply {
                    connectionTimeout = 15 * 1000
                    socketTimeout = 15 * 1000
                    maxConcurrentRequest = 5
                    maxErrorRetry = 2
                }
                val ossClient = OSSClient(this@ActivityUploadPigeonVideo, Constant.END_POINT, credentialProvider, conf)
                MultipartUploader.uploadLargeFile(
                    ossClient = ossClient,
                    bucketName = bucketName,
                    objectKey = objectKey,
                    filePath = videoUrl,
                ) { success, result ->
                    if (success) {
                        LogUtils.debugInfo( "分片上传成功，eTag: $result")
                    } else {
                        LogUtils.debugInfo( "分片上传失败，错误信息: $result")
                    }
                    dismissLoading()
                }
                if (type == 2) {
                    val bean = AddVisitVideoResponse(mPigeonId, mRaceId, objectKey)
                    mViewModel.addVisitVideoOss(bean)
                } else {
                    val bean = EditVisitVideoParam(editId, objectKey)
                    mViewModel.editVisitVideoOss(bean)
                }
            }

            override fun onProgress(percent: Float) {
                if (::dialogPro.isInitialized) {
                    dialogPro.setProgress("上传中", percent)
                }
            }

            override fun onError(code: Int, msg: String) {
                LogUtils.debugInfo(msg)
            }
        })

    }

    private fun showProgressBarDialog() {
        dialogPro = RxDialogProgressBar(this)
        dialogPro.setFullScreenWidth()
        dialogPro.setCanceledOnTouchOutside(false)
        dialogPro.show()
    }

    private fun parseCompressInfo(file: File) {
        flow<Map<String, Any>> {
            val fields = HashMap<String, Any>()
            val metadata = VideoUtils.getMetadata(file)
            fields["metadata"] = metadata
            fields[MediaStore.MediaColumns.SIZE] = file.length()
            emit(fields)
        }.flowOn(Dispatchers.IO)
            .onStart { }
            .onEach {
//                compressFile = file
//                LogUtils.debugInfo(parseInfo("压缩视频", it))
            }
            .catch { RxToast.showToast("Error: $it") }
            .onCompletion { }
            .launchIn(lifecycleScope)
    }

    @SuppressLint("DefaultLocale")
    private fun parseInfo(title: String, fields: Map<String, Any>): String {
        val sb = StringBuffer(title).append("\n\n")
        val metadata = fields["metadata"] as VideoMetadata
        val size = fields[MediaStore.MediaColumns.SIZE].toString().toLong()
        sb.append("Size: ").append(String.format("%.1fmb", size / (1024 * 1024f))).append("\n\n")
        sb.append("MimeType: ").append(metadata.mimeType).append("\n\n")
        sb.append("Width: ").append(metadata.width).append("\n\n")
        sb.append("Height: ").append(metadata.height).append("\n\n")
        sb.append("Bitrate: ").append(metadata.bitrate).append("\n\n")
        return sb.toString()
    }

    override fun onDestroy() {
        super.onDestroy()
        if (::webSocketUtils.isInitialized) {
            webSocketUtils.cancel()
        }
    }

}